﻿using CommunityToolkit.Mvvm.ComponentModel;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using HslCommunication.Profinet.Siemens;
using EV.EventBus;
using System.ComponentModel;
using DBContext;
using Autofac;
using Common;
using NLog;
using ZoneLine.Stations;
using ZoneLine.Models;
using System.Windows.Navigation;

namespace ZoneLine.Stations
{
    /// <summary>
    /// 工作站基类
    /// </summary>
    public abstract class WorkStationBase : ObservableObject
    {
        #region Fields
        
        public const string _okCode = "OK";

        private string _cycleTaskId = "";

        protected  string _logUiChannel = "debug";

        protected SiemensS7Net _client;

        public ILogger _logger = LogManager.GetCurrentClassLogger();

        public IModelDAL _dal = ContainerServer.Container.Resolve<IModelDAL>();//protected

        #endregion

        public WorkStationBase()
        {
            CurrentStationName = GetType().Name;
            _logUiChannel = CurrentStationName + "uilog";
        }


        #region Props

        private string _currentStationName;

        public string CurrentStationName
        {
            get { return _currentStationName; }
            set { _currentStationName = value; }
        }

        private bool _connectState;

        public bool ConnectState
        {
            get { return _connectState; }
            set => SetProperty(ref _connectState, value);
        }

        private string _ip;

        public string Ip
        {
            get { return _ip; }
            set => SetProperty(ref _ip, value);
        }

        private int _port;

        public int Port
        {
            get { return _port; }
            set => SetProperty(ref _port, value);
        }

        #endregion

        #region Methods

        /// <summary>
        /// 收集数据
        /// </summary>
        protected abstract void CollectData();

        /// <summary>
        /// 订阅数据地址(PLC点位交互，eg：让PLC执行什么动作)
        /// </summary>
        /// <param name="content"></param>
        protected abstract void DealDataCommon(byte[] content);

        /// <summary>
        /// 工艺数据(查询PLC数据)
        /// </summary>
        /// <param name="content"></param>
        protected abstract void DealData(byte[] content);

        /// <summary>
        /// 
        /// </summary>
        /// <param name="name"></param>
        protected abstract void DealWithSignal(string name);

        /// <summary>
        /// 记录数据
        /// </summary>
        /// <returns></returns>

        protected abstract int RecordData();

        /// <summary>
        /// 开始采集
        /// </summary>
        public virtual void Start()
        {
            if (string.IsNullOrEmpty(_cycleTaskId))
            {
                _cycleTaskId = TaskMaster.Default.AddCycleTask(5, CollectData, false, EV.EventBus.CycleTask.TimeBaseEnum._100MS);
            }
        }


        public virtual void Stop()
        {
            TaskMaster.Default.RemoveCycleTask(_cycleTaskId);
            _client.ConnectClose();
        }
       

        protected virtual void SignalAction(object sender, PropertyChangedEventArgs e)
        {
            try
            {
                var signalName = e.PropertyName;
                DealWithSignal(signalName);
            }
            catch (Exception ex)
            {
                var logChannel = CurrentStationName + "uilog";
                LogWithUi(logChannel, "信号处理异常，异常信息" + ex.Message);
            }
        }

        protected void LogWithUi(string channel, string msg, string absScanCode = "")
        {
            if (absScanCode != "")
            {
                msg = $"产品{absScanCode},{msg}";
            }
            _logger.Info(msg);
            MessageCenter.PublishAsync(channel, msg);
        }

        protected bool WriteData(string addr, bool value, string code = "")
        {
            if (string.IsNullOrEmpty(addr))
            {
                return false;
            }
            var rlt = _client.Write(addr, value).IsSuccess;

            _logger.Debug($"{_logUiChannel}，产品{code},在{CurrentStationName}工位下发数据,地址:{addr},值:{value},下发结果:{rlt}");
            var readValue = _client.ReadBool(addr).Content;
            _logger.Debug($"{_logUiChannel}，产品{code},在{CurrentStationName}工位下发数据后,读取地址:{addr},值:{readValue}");
            if (value != readValue)
            {
                LogWithUi(_logUiChannel, $"工位下发数据，下发地址：{addr}，下发值：{value}，读取到的值：{readValue}，信号通信发送存在延迟，请重试", code);
            }
            return rlt;
        }

        /// <summary>
        /// 向PLC写入数据
        /// </summary>
        /// <param name="addr">地址</param>
        /// <param name="value">值</param>
        /// <param name="code">条码</param>
        /// <param name="isRepeat">是否重发</param>
        /// <param name="isHeart">是否是心跳</param>
        /// <returns></returns>
        protected bool WriteData(string addr, short value, string code = "", bool isRepeat = false, bool isHeart = false)
        {
            if (string.IsNullOrEmpty(addr))
            {
                return false;
            }
            if (_client != null)
            {
                var rlt = _client.Write(addr, value).IsSuccess;

                _logger.Debug($"{_logUiChannel}，产品{code},在{CurrentStationName}工位下发数据,{(isHeart ? "MES心跳" : "")}地址:{addr},值:{value},下发结果:{rlt}");

                var readValue = _client.ReadInt16(addr).Content;

                _logger.Debug($"{_logUiChannel}，产品{code},在{CurrentStationName}工位下发数据后,读取{(isHeart ? "MES心跳" : "")}地址:{addr},值:{readValue}");

                if (isRepeat && value != readValue)
                {
                    LogWithUi(_logUiChannel, $"在{CurrentStationName}工位下发数据，下发{(isHeart ? "MES心跳" : "")}地址：{addr}，下发值：{value}，读取到的值：{readValue}，信号通信发送存在延迟，正在重试", code);

                    _logger.Error($"在{CurrentStationName}工位下发数据，下发{(isHeart ? "MES心跳" : "")}地址：{addr}，下发值：{value}，读取到的值：{readValue}，信号通信发送存在延迟，正在重试", code);

                    while (value != readValue)
                    {
                        LogWithUi(_logUiChannel, $"在{CurrentStationName}工位下发数据，由于网络正在重新下发", code);

                        _logger.Error($"在{CurrentStationName}工位下发数据，由于网络正在重新下发", code);

                        rlt = _client.Write(addr, value).IsSuccess;

                        readValue = _client.ReadInt16(addr).Content;

                        System.Threading.Thread.Sleep(500);
                    }
                }
                return rlt;
            }
            return false;
        }

        protected bool WriteData(string addr, string value, string code = "")
        {
            if (string.IsNullOrEmpty(addr))
            {
                return false;
            }
            if (_client != null)
            {
                var rlt = _client.Write(addr, value).IsSuccess;

                _logger.Debug($"{_logUiChannel}，产品{code},在{CurrentStationName}工位下发数据,地址:{addr},值:{value},下发结果:{rlt}");
                var readValue = _client.ReadString(addr).Content;
                _logger.Debug($"{_logUiChannel}，产品{code},在{CurrentStationName}工位下发数据后,读取地址:{addr},值:{readValue}");
                if (value != readValue)
                {
                    LogWithUi(_logUiChannel, $"工位下发数据，下发地址：{addr}，下发值：{value}，读取到的值：{readValue}，信号通信发送存在延迟，请重试", code);
                }
                return rlt;
            }
            return false;
        }

        protected virtual WorkActionEnum Validata(string stationName, string code, string[] otherStations = null)
        {
            var currentStationName = stationName;
            var stationIndex = Cache.WorkStationValidationList.IndexOf(currentStationName);
            if (stationIndex == -1)
            {
                return WorkActionEnum.NoEnable;
            }
            if (stationIndex > 0)
            {
                //检测上一个站
                var beforeStationName = Cache.WorkStationValidationList[stationIndex - 1];
                LogWithUi(_logUiChannel, $"在{currentStationName}工位上一个启动的检查工位是{beforeStationName}", code);
                var checkRlt = CheckCodeExistAndResult(beforeStationName, code);
                LogWithUi(_logUiChannel, $"在{beforeStationName}工位检查{code}的结论是{checkRlt}", code);
                if (checkRlt == 1)
                {
                    if (otherStations != null)
                    {
                        LogWithUi(_logUiChannel, $"在上个工位{beforeStationName}工位检查{code}的结论是{checkRlt},开始检查校验工位结论", code);
                        foreach (var otherStation in otherStations)
                        {
                            LogWithUi(_logUiChannel, $"{currentStationName}检查校验工位{otherStation}是否工作", code);
                            var otherStationResult = CheckCodeExistAndResult(otherStation, code);
                            if (otherStationResult == 1)
                            {
                                LogWithUi(_logUiChannel, $"{currentStationName}检查校验工位{otherStation}工作过，不在本工位进行工作", code);
                                return WorkActionEnum.WorkOkInCheckStation;
                            }
                        }
                    }
                    LogWithUi(_logUiChannel, $"在上个工位{beforeStationName}工位检查{code}的结论是{checkRlt},开始检查是否在本工位{currentStationName}结论", code);
                    var currentResult = CheckCodeExistAndResult(currentStationName, code);
                    LogWithUi(_logUiChannel, $"在本工位{currentStationName}工位检查{code}的结论是{currentResult}", code);
                    if (currentResult == 1)
                    {
                        return WorkActionEnum.HasWorkInCurrent;
                    }
                    else
                    {
                        return WorkActionEnum.StartWork;
                    }
                }
                else if (checkRlt == 2)
                {
                    return WorkActionEnum.WorkNgInBefore;
                }
                else
                {
                    return WorkActionEnum.NotWorkInBefore;
                }
            }
            else
            {
                //检查当前工位
                if (otherStations != null)
                {
                    LogWithUi(_logUiChannel, $"在{currentStationName}工位不存在上个工位，检查并行工位工作结论", code);

                    foreach (var otherStation in otherStations)
                    {
                        LogWithUi(_logUiChannel, $"{currentStationName}检查校验工位{otherStation}是否工作", code);
                        var otherStationResult = CheckCodeExistAndResult(otherStation, code);
                        if (otherStationResult == 1)
                        {
                            LogWithUi(_logUiChannel, $"{currentStationName}检查校验工位{otherStation}工作过，不在本工位进行工作", code);
                            return WorkActionEnum.WorkOkInCheckStation;
                        }
                    }
                }
                LogWithUi(_logUiChannel, $"在{currentStationName}工位不存在上个工位，检查在本工位工作结论", code);
                var checkResult = CheckCodeExistAndResult(currentStationName, code);
                if (checkResult == 1)
                {
                    return WorkActionEnum.HasWorkInCurrent;
                }
                else
                {
                    return WorkActionEnum.StartWork;
                }
            }
        }


        protected virtual bool WriteWorkActionToPlc(string addr, WorkActionEnum work, string code = "",bool isRepeat = false)
        {
            return WriteData(addr, (short)work, code, isRepeat);

            #region old
            //switch (work)
            //{
            //    case WorkActionEnum.StartWork:
            //        {
            //            var result = _client.Write(addr, (short)1);
            //            return result.IsSuccess;
            //        }
            //    case WorkActionEnum.HasWorkInCurrent:
            //        {
            //            var result = _client.Write(addr, (short)2);
            //            return result.IsSuccess;
            //        }
            //    //break;
            //    case WorkActionEnum.NotWorkInBefore:
            //        {
            //            var result = _client.Write(addr, (short)3);
            //            return result.IsSuccess;
            //        }
            //    //break;
            //    case WorkActionEnum.WorkNgInBefore:
            //        {
            //            var result = _client.Write(addr, (short)4);
            //            return result.IsSuccess;
            //        }
            //    //break;
            //    case WorkActionEnum.NoEnable:
            //        {
            //            var result = _client.Write(addr, (short)5);
            //            return result.IsSuccess;
            //        }
            //    //break;
            //    case WorkActionEnum.CalHErr:
            //        {
            //            var result = _client.Write(addr, (short)6);
            //            return result.IsSuccess;
            //        }
            //    //break;
            //    case WorkActionEnum.WorkOkInCheckStation:
            //        {
            //            var result = _client.Write(addr, (short)2);
            //            return result.IsSuccess;
            //        }
            //    //break;
            //    default:
            //        return false;
            //}
            #endregion

        }


        /// <summary>
        /// 检查该工件在这个工位是否加工以及加工结论
        /// </summary>
        /// <param name="stationCode"></param>
        /// <param name="code"></param>
        /// <returns>0，表示未加工作，1表示加工OK，2表示加工但是加工NG</returns>
        /// <exception cref="Exception"></exception>
        protected virtual int CheckCodeExistAndResult(string stationCode, string code)
        {
            switch (stationCode)
            {
                //todo 补充所有的工位
                case nameof(QOP006Station):
                    {
                        var op006Result = _dal.GetModel<QOP006StationResult>(p => p.AbsScanCode == code);
                        if (op006Result == null)
                        {
                            return 0;
                        }
                        else if (op006Result.Result == _okCode)
                        {
                            return 1;
                        }
                        else
                        {
                            return 2;
                        }
                    }
                case nameof(QOP010Station):
                    {
                        var op010Result = _dal.GetModel<QOP010StationResult>(p => p.AbsScanCode == code);
                        if (op010Result == null)
                        {
                            return 0;
                        }
                        else if (op010Result.Result == _okCode)
                        {
                            return 1;
                        }
                        else
                        {
                            return 2;
                        }
                    }

                case nameof(QOP020Station):
                    var op020Result = _dal.GetModel<QOP020StationResult>(p => p.AbsScanCode == code);
                    if (op020Result == null)
                    {
                        return 0;
                    }
                    else if (op020Result.Result == _okCode)
                    {
                        return 1;
                    }
                    else
                    {
                        return 2;
                    }


                case nameof(QOP050LStation):
                case nameof(QOP050RStation):
                    var op050LResult = _dal.GetModel<QOP050LStationResult>(p => p.AbsScanCode == code);
                    var op050RResult = _dal.GetModel<QOP050RStationResult>(p => p.AbsScanCode == code);
                    if (op050LResult == null && op050RResult == null)
                    {
                        return 0;
                    }
                    else if ((op050LResult != null && op050LResult.Result == _okCode) || (op050RResult != null && op050RResult.Result == _okCode))
                    {
                        return 1;
                    }
                    else
                    {
                        return 2;
                    }
                case nameof(HOP010Station):
                    var hOp010Result = _dal.GetModel<HOP010StationResult>(p => p.AbsScanCode == code);
                    if (hOp010Result == null)
                    {
                        return 0;
                    }
                    else if (hOp010Result.Result == _okCode)
                    {
                        return 1;
                    }
                    else
                    {
                        return 2;
                    }
                case nameof(HOP040Station):
                    var hOp040Result = _dal.GetModel<HOP040StationResult>(p => p.AbsScanCode == code);
                    if (hOp040Result == null)
                    {
                        return 0;
                    }
                    else if (hOp040Result.Result == _okCode)
                    {
                        return 1;
                    }
                    else
                    {
                        return 2;
                    }
                //break;

                default: 
                    throw new Exception("not exist station");
            }

        }

        #region 注释

        //protected virtual void Validata(string code, string allowWriteAddr)
        //{
        //    var currentStationName = GetType().Name;
        //    var logChannel = currentStationName + "uilog";
        //    LogWithUi(logChannel, $"在{currentStationName}工位结论验证,条码信息是{code}");
        //    //if (Validate == null || Validate.EnableValidate != 1)
        //    //{
        //    //     LogWithUi(logChannel,($"在{currentStationName}工位未配置验证，工件允许工作，向下位机写入信息");
        //    //    var writeRlt = AllowPlcToWork();
        //    //     LogWithUi(logChannel,($"在{currentStationName}工位写入信息{writeRlt}");
        //    //    return;
        //    //}
        //    var stationIndex = Cache.WorkStationValidationList.IndexOf(currentStationName);
        //    if (stationIndex == -1)
        //    {
        //        LogWithUi(logChannel, $"在{currentStationName}工位没有配置启用，请检查");
        //        var writeRlt = WriteWorkActionToPlc(allowWriteAddr, WorkActionEnum.NoEnable);
        //        LogWithUi(logChannel, $"在{currentStationName}工位没有配置启用，下发命令的状态是{writeRlt}");
        //        return;
        //    }
        //    if (stationIndex > 0)
        //    {
        //        //检测上一个站
        //        var beforeStationName = Cache.WorkStationValidationList[stationIndex - 1];
        //        LogWithUi(logChannel, $"在{currentStationName}工位上一个启动的检查工位是{beforeStationName}");
        //        var checkRlt = CheckCodeExistAndResult(beforeStationName, code);
        //        LogWithUi(logChannel, $"在{beforeStationName}工位检查{code}的结论是{checkRlt}");
        //        if (checkRlt == 1)
        //        {
        //            LogWithUi(logChannel, $"在上个工位{beforeStationName}工位检查{code}的结论是{checkRlt},开始检查是否在本工位{currentStationName}结论");
        //            var currentResult = CheckCodeExistAndResult(currentStationName, code);
        //            LogWithUi(logChannel, $"在本工位{currentStationName}工位检查{code}的结论是{currentResult}");
        //            if (currentResult == 1)
        //            {
        //                LogWithUi(logChannel, $"在本工位{currentStationName}工位检查{code}的结论是{currentResult}不允许工作，下发信号");
        //                var writeRlt = WriteWorkActionToPlc(allowWriteAddr, WorkActionEnum.HasWorkInCurrent);
        //                LogWithUi(logChannel, $"在本工位{currentStationName}工位检查{code}的结论是{currentResult}不允许工作，下发信号的结果是{writeRlt}");
        //            }
        //            else
        //            {
        //                LogWithUi(logChannel, $"在本工位{currentStationName}工位检查{code}的结论是{currentResult}允许工作，下发信号");
        //                var writeRlt = WriteWorkActionToPlc(allowWriteAddr, WorkActionEnum.StartWork);
        //                LogWithUi(logChannel, $"在本工位{currentStationName}工位检查{code}的结论是{currentResult}允许工作，下发信号的结果是{writeRlt}");
        //            }
        //            return;
        //        }
        //        else if (checkRlt == 2)
        //        {
        //            LogWithUi(logChannel, $"在{beforeStationName}工位检查{code}的结论是{checkRlt},不允许在本工位工作");
        //            var writeRlt = WriteWorkActionToPlc(allowWriteAddr, WorkActionEnum.WorkNgInBefore);
        //            LogWithUi(logChannel, $"在{beforeStationName}工位检查{code}的结论是{checkRlt},不允许在本工位工作下发plc结论是{writeRlt}");
        //        }
        //        else
        //        {
        //            LogWithUi(logChannel, $"在{beforeStationName}工位检查{code}的结论是{checkRlt},不允许在本工位工作");
        //            var writeRlt = WriteWorkActionToPlc(allowWriteAddr, WorkActionEnum.NotWorkInBefore);
        //            LogWithUi(logChannel, $"在{beforeStationName}工位检查{code}的结论是{checkRlt},不允许在本工位工作下发plc结论是{writeRlt}");
        //        }
        //    }
        //    else
        //    {
        //        //检查当前工位
        //        LogWithUi(logChannel, $"在{currentStationName}工位不存在上个工位，检查在本工位工作结论");
        //        var checkResult = CheckCodeExistAndResult(currentStationName, code);
        //        if (checkResult == 1)
        //        {
        //            LogWithUi(logChannel, $"在{currentStationName}工位检查结论是{checkResult},下发不可以工作命令");
        //            var rlt = WriteWorkActionToPlc(allowWriteAddr, WorkActionEnum.HasWorkInCurrent);
        //            LogWithUi(logChannel, $"在{currentStationName}工位检查结论是{checkResult},下发不可以工作命令的结果是{rlt}");

        //        }
        //        else
        //        {
        //            LogWithUi(logChannel, $"在{currentStationName}工位检查结论是{checkResult},下发可以工作命令");
        //            var rlt = WriteWorkActionToPlc(allowWriteAddr, WorkActionEnum.StartWork);
        //            LogWithUi(logChannel, $"在{currentStationName}工位检查结论是{checkResult},下发可以工作命令的结果是{rlt}");
        //        }
        //    }
        //}

        //protected virtual WorkActionEnum Validata(string code)
        //{
        //    var currentStationName = GetType().Name;
        //    var logChannel = currentStationName + "uilog";

        //    var stationIndex = Cache.WorkStationValidationList.IndexOf(currentStationName);
        //    if (stationIndex == -1)
        //    {
        //        return WorkActionEnum.NoEnable;
        //    }
        //    if (stationIndex > 0)
        //    {
        //        //检测上一个站
        //        var beforeStationName = Cache.WorkStationValidationList[stationIndex - 1];
        //        LogWithUi(logChannel, $"在{currentStationName}工位上一个启动的检查工位是{beforeStationName}");
        //        var checkRlt = CheckCodeExistAndResult(beforeStationName, code);
        //        LogWithUi(logChannel, $"在{beforeStationName}工位检查{code}的结论是{checkRlt}");
        //        if (checkRlt == 2)
        //        {
        //            LogWithUi(logChannel, $"在上个工位{beforeStationName}工位检查{code}的结论是{checkRlt},开始检查是否在本工位{currentStationName}结论");
        //            var currentResult = CheckCodeExistAndResult(currentStationName, code);
        //            LogWithUi(logChannel, $"在本工位{currentStationName}工位检查{code}的结论是{currentResult}");
        //            if (currentResult == 2)
        //            {
        //                LogWithUi(logChannel, $"在本工位{currentStationName}工位检查{code}的结论是{currentResult}不允许工作，下发信号");
        //                return WorkActionEnum.HasWorkInCurrent;
        //            }
        //            else
        //            {
        //                LogWithUi(logChannel, $"在本工位{currentStationName}工位检查{code}的结论是{currentResult}允许工作，下发信号");
        //                return WorkActionEnum.StartWork;
        //            }
        //        }
        //        else if (checkRlt == 1)
        //        {
        //            LogWithUi(logChannel, $"在{beforeStationName}工位检查{code}的结论是{checkRlt},不允许在本工位工作");
        //            return WorkActionEnum.WorkNgInBefore;
        //        }
        //        else
        //        {
        //            LogWithUi(logChannel, $"在{beforeStationName}工位检查{code}的结论是{checkRlt},不允许在本工位工作");
        //            return WorkActionEnum.NotWorkInBefore;
        //        }
        //    }
        //    else
        //    {
        //        //检查当前工位
        //        LogWithUi(logChannel, $"在{currentStationName}工位不存在上个工位，检查在本工位工作结论");
        //        var checkResult = CheckCodeExistAndResult(currentStationName, code);
        //        if (checkResult == 2)
        //        {
        //            LogWithUi(logChannel, $"在{currentStationName}工位检查结论是{checkResult},下发不可以工作命令");
        //            return WorkActionEnum.HasWorkInCurrent;

        //        }
        //        else
        //        {
        //            LogWithUi(logChannel, $"在{currentStationName}工位检查结论是{checkResult},下发可以工作命令");
        //            return WorkActionEnum.StartWork;
        //        }
        //    }
        //}
        #endregion

        #endregion
    }
}
